package com.example.myapplication.base;


import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;

public final class ArgUtils {

    private ArgUtils() {
    }

    /**
     * 校验参数是否不为Null。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数为Null。
     */
    public static void checkNonNull(String name, Object parameter) {
        if (parameter == null) {
            throwIllegalArgumentException("Parameter " + name + " must not be null");
        }
    }

    /**
     * 校验字符串/数组/{@link Collection}参数是否不为Null且非空。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数为Null或为空字符串/空数组/空的{@link Collection}。
     */
    public static void checkNotEmpty(String name, Object parameter) {
        boolean empty = parameter == null
                || (parameter instanceof CharSequence && ((CharSequence) parameter).length() == 0)
                || (parameter instanceof Collection && ((Collection) parameter).isEmpty())
                || (parameter.getClass().isArray() && Array.getLength(parameter) == 0);
        if (empty) {
            throwIllegalArgumentException("Parameter " + name + " must not be empty");
        }
    }

    /**
     * 校验数组/{@link Collection}参数中是否不包含Null。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数不为Null且数组/{@link Collection}中包含Null。
     */
    public static void checkNotContainsNull(String name, Object parameter) {
        if (parameter instanceof Object[]) {
            checkNotContainsNull(name, Arrays.asList((Object[]) parameter));
        } else if (parameter instanceof Collection && ((Collection) parameter).contains(null)) {
            throwIllegalArgumentException("Parameter " + name + " must not contain null");
        }
    }

    /**
     * 校验数组/{@link Collection}参数中是否不包含重复的元素。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数不为Null且数组/{@link Collection}中包含重复的元素。
     */
    public static void checkNotContainsDuplicates(String name, Object parameter) {
        if (parameter instanceof Collection) {
            checkNotContainsDuplicates(name, ((Collection) parameter).toArray());
        } else if (parameter.getClass().isArray()) {
            final int length = Array.getLength(parameter);
            for (int i = 0; i < length; i++) {
                for (int j = i + 1; j < length; j++) {
                    if (Objects.equals(Array.get(parameter, i), Array.get(parameter, j))) {
                        throwIllegalArgumentException("Parameter " + name + " must not contain duplicates");
                    }
                }
            }
        }
    }

    /**
     * 校验参数中是否为正数。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数不为正数。
     */
    public static void checkPositive(String name, long parameter) {
        if (parameter <= 0) {
            throwIllegalArgumentException("Parameter " + name + " must be positive");
        }
    }

    /**
     * 校验参数中是否为正数。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数不为正数。
     */
    public static void checkPositive(String name, double parameter) {
        if (parameter <= 0.0) {
            throwIllegalArgumentException("Parameter " + name + " must be positive");
        }
    }

    /**
     * 校验参数中是否为负数。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数不为负数。
     */
    public static void checkNegative(String name, long parameter) {
        if (parameter >= 0) {
            throwIllegalArgumentException("Parameter " + name + " must be negative");
        }
    }

    /**
     * 校验参数中是否为负数。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数不为负数。
     */
    public static void checkNegative(String name, double parameter) {
        if (parameter >= 0.0) {
            throwIllegalArgumentException("Parameter " + name + " must be negative");
        }
    }

    /**
     * 校验参数中是否为非正数。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数为正数。
     */
    public static void checkNonPositive(String name, long parameter) {
        if (parameter > 0) {
            throwIllegalArgumentException("Parameter " + name + " must not be positive");
        }
    }

    /**
     * 校验参数中是否为非正数。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数为正数。
     */
    public static void checkNonPositive(String name, double parameter) {
        if (parameter > 0.0) {
            throwIllegalArgumentException("Parameter " + name + " must not be positive");
        }
    }

    /**
     * 校验参数中是否为非负数。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数为负数。
     */
    public static void checkNonNegative(String name, long parameter) {
        if (parameter < 0) {
            throwIllegalArgumentException("Parameter " + name + " must not be positive");
        }
    }

    /**
     * 校验参数中是否为非负数。
     *
     * @param name      参数名。
     * @param parameter 参数值。
     * @throws IllegalArgumentException 如果参数为负数。
     */
    public static void checkNonNegative(String name, double parameter) {
        if (parameter < 0.0) {
            throwIllegalArgumentException("Parameter " + name + " must not be positive");
        }
    }

    private static void throwIllegalArgumentException(String message) {
        final IllegalArgumentException e = new IllegalArgumentException(message);
        final StackTraceElement[] stackTrace = e.getStackTrace();
        final int size = stackTrace.length;
        int lastArgUtils = -1;
        for (int i = 0; i < size; i++) {
            if (ArgUtils.class.getName().equals(stackTrace[i].getClassName())) {
                lastArgUtils = i;
            }
        }
        final StackTraceElement[] newStackTrace =
                Arrays.copyOfRange(stackTrace, lastArgUtils + 1, size);
        e.setStackTrace(newStackTrace);
        throw e;
    }

}
